#include "dvbinner.h"
#include "dvbepgdb.h"
#include "dvbepg.h"

dvb_handle_t Mutex_DvbEpg = (dvb_handle_t)NULL;	
static dvb_handle_t epgThread=(dvb_handle_t)NULL;
static pEitCallback EitChgCallback = NULL;
static unsigned char u8EPGReceiving = 0;
static unsigned char u8EPGRecvMode = SIACTURAL;

int DVBEPGStop()
{
	u8EPGReceiving = 0;
}

int DVBEPGStart()
{
	u8EPGReceiving = 1;
}

int DVBEPGSetRecvMode(int mode)
{
	return u8EPGRecvMode;	
}

static unsigned int  DVBEPGGetEitDurate(unsigned int EitDuration)
{
	 unsigned int    duration;
	 unsigned int    minute,hour,second;

	 second = EitDuration & 0xFF ;
	 second = (second/16)*10+second%16 ;
	 minute = ((EitDuration)>>8)&0xFF;
	 minute = (minute/16)*10+(minute%16);
	 hour = (((EitDuration)>>16)&0xFF);
	 hour = (hour/16)*10+(hour%16);
	 duration = hour*3600+minute*60+second;
	 return 	duration;
}

static int DVBEPGEitChangeNotify(unsigned char* pSection)
{
	unsigned short netid,tsid,sid;
	unsigned int freq;
	dvb_service_t sd;
	
	netid = SiPsiEITGetNetID(pSection);
	tsid = SiPsiEITGetStreamID(pSection);
	sid = SiPsiEITGetServiceID(pSection);
	freq = GetCurFrequency();
	sd = DvbGetCurService();
	if(netid==sd.netId && tsid==sd.tsId 
	&& sid==sd.serviceId && freq==sd.frequence)
	{
		if(EitChgCallback)
			EitChgCallback(&sd);
	}
	return 0;
}

void DVBRecvEitTask()
{
	char section[4096+20];
	unsigned short Secchar[16];
	static dvb_handle_t hMsgque_Eits=(dvb_handle_t)NULL;
	dvb_handle_t hFilter;
	SCHEDULE		*sch;
	SECTIONDATA 	*sd;
	unsigned char mask[8],data[8];
	unsigned char table_id,sno;
	int ret,i,secCount=0,failed=0;
	unsigned short netid,tsid,sid;
	filter_param_t filterParam;
	unsigned int freq;
 	
	if (!hMsgque_Eits)
	{
		hMsgque_Eits = mwOsCreateMessage(20,4096);
	}
	mask[0]=0xE0;
	data[0]=SIPSI_TID_EIT_ACTUAL_PF;
	memset(Secchar,0,16*2);
	for (i=0;i<1;i++)
		Secchar[i]=data[i] + (mask[i]<<8);
	
	filterParam.m_u8CrcCheck = 1;
	filterParam.m_u8FilterDepth = 1;
	filterParam.m_pfCb = NULL;	
	filterParam.m_u16Pid = SIPSI_PID_EIT;
	filterParam.m_pu16SectByte = Secchar;
	filterParam.m_hQueueID = hMsgque_Eits;
	ret=mwDmxStartFilter(&filterParam,&hFilter);
	if(ret != 0)
	{
		mwDebug("DVBRecvEit() - start filter fail***************\r\n");
	}
	while (1)
	{
		if (mwOsReceiveMessage(hMsgque_Eits, section, 4096, 5000)==0)	
		{
			netid=SiPsiEITGetNetID(section);
			 tsid=SiPsiEITGetStreamID(section);
			sid=SiPsiEITGetServiceID(section);

			table_id=SiPsiGetTableID(section);
			if((table_id < SIPSI_TID_EIT_ACTUAL_PF)||(table_id > 0x6F))
			{
				mwDebug("EIT TableID= [0x%02X] Error,pid=%d\r\n",table_id,ret);
				printHex(section, 16);
				mwOsSleep(5);
				continue;
			}
			if (table_id ==SIPSI_TID_EIT_ACTUAL_PF ||table_id ==SIPSI_TID_EIT_OTHER_PF )
			{
				mwOsMutexLock(Mutex_DvbEpg);
				AddSectionToDB(DVBEPGGetPFDB(),section);
				mwOsMutexUnlock(Mutex_DvbEpg);
			}
			else if (table_id >= 0x50 && table_id <= 0x5F)
			{
				sch = DVBEPGGetScheduleSlot(netid,tsid,sid);
				sno=SiPsiGetSectionNo(section);
				sd=FindIsSameSectionDB(sch->sections,section);
				mwOsMutexLock(Mutex_DvbEpg);
				AddSectionToDB(sch->sections,section);
				mwOsMutexUnlock(Mutex_DvbEpg);
				if(!sd)
				{
					DVBEPGEitChangeNotify(section);
				}
			}	
			else if (table_id>=0x60 && table_id <=0x6F)
			{
				if (u8EPGRecvMode == SIBOTH)
				{
					sch = DVBEPGGetScheduleSlot(netid,tsid,sid);
					sno=SiPsiGetSectionNo(section);
					sd=FindIsSameSectionDB(sch->sections,section);
					mwOsMutexLock(Mutex_DvbEpg);
					AddSectionToDB(sch->sections,section);
					mwOsMutexUnlock(Mutex_DvbEpg);
				}	
			}
			secCount++;
		}
		else
		{
			failed++;
			mwOsSleep(50);
			if (failed >2)
			{
				failed=0;
				mwDmxStopFilter(hFilter);
				ret=mwDmxStartFilter(&filterParam, &hFilter);
			}
		}
		if (u8EPGReceiving == 0)
		{	
			mwDebug("Recv Eit stop #####################\r\n");
			mwDmxStopFilter(hFilter);
			while (u8EPGReceiving == 0)
			{
				mwOsSleep(50);	
			}
			mwDebug("Recv Eit Restart #####################\r\n");
			mwOsEmptyMessage(hMsgque_Eits);
			ret = mwDmxStartFilter(&filterParam,&hFilter);
			while(ret != 0)
			{
				mwDebug("Start recv EIT fail\r\n");
				mwOsSleep(50);
				ret = mwDmxStartFilter(&filterParam,&hFilter);
			}
 		}
		mwOsSleep(5);
	}

	mwDmxStopFilter(hFilter);
	mwOsDeleteMessage(hMsgque_Eits);
}

int DVBEPGEitChg(sipsi_dvbevent_t *evt, dvb_event_t* peitinfo)
{
	unsigned char lang[4];
	int s32CurTimezone = 8;
	unsigned int u32StringLen;
	
	if (evt && peitinfo)	
	{
		memset(peitinfo,0,sizeof(dvb_event_t) );
		peitinfo->event_id=evt->m_u16EventId;
		SiPsiConvertToSysTime((sipsi_systime_t*)&peitinfo->StartTime, evt->m_u16MjdDate, evt->m_u32UtcTime);
		DVBSysDBGetTimezone(&s32CurTimezone);
		peitinfo->StartTime = GetEndTime(peitinfo->StartTime,60*30*s32CurTimezone);
		peitinfo->duration = DVBEPGGetEitDurate(evt->m_u32Duration);
		peitinfo->EndTime = GetEndTime(peitinfo->StartTime, peitinfo->duration);
		mwDebug("EitChg --------- %2d %2d %2d %2d ",peitinfo->StartTime.month,peitinfo->StartTime.mday,peitinfo->StartTime.hour,peitinfo->StartTime.minute);

		SiPsiEITGetShortEventName(evt,(unsigned char*)peitinfo->EventName,peitinfo->Desc,lang);
		u32StringLen = DVBStringLen(peitinfo->EventName);
		if(u32StringLen > 0)
		{
			if(u32StringLen > sizeof(peitinfo->EventName))
				u32StringLen = sizeof(peitinfo->EventName) - 2;
			mwConvertString(peitinfo->EventName, u32StringLen, NULL);
		}
		
		memcpy(peitinfo->lang, lang, 4);
		SiPsiEITGetExtendEventName(evt, (unsigned char*)peitinfo->ExtendDesc, NULL);
		u32StringLen = DVBStringLen(peitinfo->EventName);
		if(u32StringLen > 0)
		{
			if(u32StringLen > sizeof(peitinfo->ExtendDesc))
				u32StringLen = sizeof(peitinfo->ExtendDesc) - 2;
			mwConvertString(peitinfo->ExtendDesc, u32StringLen, NULL);
		}
		peitinfo->running_status=evt->m_u32RuningStatus;
	}
	else
	{
		mwError("DVBEPGEitChg() - receive error param\r\n");
	}
	return 0;
}

int DVBEPGGetInfobyService(dvb_service_t* handle, sipsi_dvbevent_t *evt,int type)
{
	SECTIONDB		*sdb;
	SECTIONDATA	*sd;
	unsigned short networkid, transstreamid,serviceid;
	int i,ret=0,secFind=0,secno;
	unsigned int evtCnt = 0;

	mwDebug("DVBEPGGetInfobyService() - entry\r\n");
	if (!handle)	return -1;
	memset(evt, 0, sizeof(sipsi_dvbevent_t));

	mwOsMutexLock(Mutex_DvbEpg);
	sdb = DVBEPGGetPFDB();
	if(sdb)
	{
		i=0;
		sd=sdb->sections;
		
		while(sd && sd->Data && secFind <2)
		{
			networkid = SiPsiEITGetNetID(sd->Data);
			transstreamid = SiPsiEITGetStreamID(sd->Data);
			serviceid = SiPsiEITGetServiceID(sd->Data);
			secno = SiPsiGetSectionNo(sd->Data);

			if( handle->netId==networkid && handle->tsId==transstreamid  && handle->serviceId==serviceid)
			{
				int count = SiPsiEITGetEventCount(sd->Data);
				secFind++;
				if(count >0)
				{
					SiPsiEITGetEvent(sd->Data, evt, 0);
					if (secno==type)
					{
						mwOsMutexUnlock(Mutex_DvbEpg);
						mwDebug("DVBEPGGetInfobyService() - return 0 \r\n");
						return 0;
					}
					ret++;
				}
				evtCnt += count;
			}
			sd=sd->next;
		}
	}
	mwOsMutexUnlock(Mutex_DvbEpg);
	
	mwDebug("DVBEPGGetInfobyService() - return 1 \r\n");
	if(!evtCnt)
		return -1;
	return (secFind==0)?-1:ret;
}

int DVBEPGCheckEitInfo(dvb_event_t* peitinfo, int type)
{
	int ret = -1;

	mwDebug("DVBEPGCheckEitInfo() - type = %d--- %02d-%02d %02d:%02d~%02d-%02d %02d:%02d", type,
		peitinfo->StartTime.month,peitinfo->StartTime.mday,peitinfo->StartTime.hour,peitinfo->StartTime.minute,
		peitinfo->EndTime.month,peitinfo->EndTime.mday,peitinfo->EndTime.hour,peitinfo->EndTime.minute);
	switch(type)
	{
		case 0:
			if(CompareTime(peitinfo->EndTime, DVBGetSystemTime()) <= 0)//endtime > curtime
				ret = 0;
			break;
		case 1:
			if(CompareTime(peitinfo->StartTime, DVBGetSystemTime()) <= 0)//starttime > curtime
				ret = 0;
			break;
		default:
			break;
	}
	return ret;
}

int DVBEPGGetEitInfo(dvb_service_t* handle, DVB_EIT_T type, dvb_event_t* peitinfo)
{
	sipsi_dvbevent_t evt;
	int ret;

	memset(peitinfo,0,sizeof(dvb_event_t));
	memset(&evt, 0, sizeof(sipsi_dvbevent_t));
	ret=DVBEPGGetInfobyService(handle,&evt,type);
	if (ret == 0)
	{
		ret = DVBEPGEitChg(&evt,peitinfo);
		if(ret == 0)
			return DVBEPGCheckEitInfo(peitinfo, type);
	}
	return -1;
}

int DVBEPGGetScheEventCount(dvb_service_t* SerHandle)
{
	SECTIONDB *db;
	SECTIONDATA *sd;
	int ec,evtCount=0;

	mwOsMutexLock(Mutex_DvbEpg);
	db = DVBEPGGetScheduleDB(SerHandle);
	if(db!=NULL)
	{
		sd=db->sections;
		while(sd && sd->Data)
		{
			ec=SiPsiEITGetEventCount(sd->Data);			
			evtCount+=ec;
			sd=sd->next;
		}
	}
	mwOsMutexUnlock(Mutex_DvbEpg);
	return evtCount;
}

int DVBEPGGetWeekdayScheEventCount(dvb_service_t* SerHandle, unsigned char weekday)
{
	SECTIONDB *db;
	SECTIONDATA *sd;
	int ec,evtCount=0;
	int i;
	sipsi_dvbevent_t evt;
	dvb_event_t evtInfo;

	if(weekday<1&&weekday>7)
	{
		mwDebug("DVBEPGGetWeekdayScheEventCount() - error weekday\r\n");
	}
	else
	{
		mwOsMutexLock(Mutex_DvbEpg);
		db = DVBEPGGetScheduleDB(SerHandle);
		if(db!=NULL)
		{
			sd=db->sections;
			while(sd && sd->Data)
			{
				ec=SiPsiEITGetEventCount(sd->Data);
				for(i=0; i<ec; i++)
				{
					SiPsiEITGetEvent(sd->Data, &evt, i);
					DVBEPGEitChg(&evt,&evtInfo);
					if(evtInfo.StartTime.wday == weekday)
					{
						dvb_time_t Curtime;
						Curtime=DVBGetSystemTime();//add by wangxr  the next weekday remove,only this weekday
						if((evtInfo.StartTime.mday>=Curtime.mday)&&(evtInfo.StartTime.mday-Curtime.mday)<7)
						{	
							//add by rfwu, remove  overdue EPG event			
							if(evtInfo.StartTime.mday == Curtime.mday){
								if((evtInfo.EndTime.hour > Curtime.hour) || (evtInfo.EndTime.hour == Curtime.hour &&
									evtInfo.EndTime.minute > Curtime.minute)){
									evtCount++;
								}
							}else{
								evtCount++;
							}
						}
					}
				}
				sd=sd->next;
			}
		}
		mwOsMutexUnlock(Mutex_DvbEpg);
	}
	return evtCount;
}

int DVBEPGGetScheInfo(dvb_service_t* SerHandle, int index, dvb_event_t* peitinfo)
{
	SECTIONDB *db;
	SECTIONDATA *sd;
	sipsi_dvbevent_t evt;
	int i,ec,evtCount=0;

	mwOsMutexLock(Mutex_DvbEpg);
	db = DVBEPGGetScheduleDB(SerHandle);
	if(db!=NULL)
	{
		sd=db->sections;
		while(sd)
		{
			ec=SiPsiEITGetEventCount(sd->Data);			
			for(i=0; i<ec; i++)
			{
				if (index==evtCount)
				{
					SiPsiEITGetEvent(sd->Data, &evt, i);
					DVBEPGEitChg(&evt,peitinfo);
					mwOsMutexUnlock(Mutex_DvbEpg);
					return 0;
				}
				evtCount++;
			}
			sd=sd->next;
		}
	}
	mwOsMutexUnlock(Mutex_DvbEpg);
	return -1;
}

int DVBEPGGetWeekdayScheInfo(dvb_service_t* SerHandle,int index,unsigned char weekday, dvb_event_t* peitinfo)
{
	SECTIONDB *db;
	SECTIONDATA *sd;
	sipsi_dvbevent_t evt;
	int i,ec,evtCount=0;

	if(weekday>0 && weekday<8)
	{
		mwOsMutexLock(Mutex_DvbEpg);
		db = DVBEPGGetScheduleDB(SerHandle);
		if(db!=NULL)
		{
			sd=db->sections;
			while(sd)
			{
				ec=SiPsiEITGetEventCount(sd->Data);			
				for(i=0; i<ec; i++)
				{
					SiPsiEITGetEvent(sd->Data, &evt, i);
					DVBEPGEitChg(&evt,peitinfo);
					if(peitinfo->StartTime.wday == weekday)
					{
						dvb_time_t Curtime;
						Curtime=DVBGetSystemTime();//add by wangxr  the next weekday remove,only this weekday
						if((peitinfo->StartTime.mday>=Curtime.mday)&&(peitinfo->StartTime.mday-Curtime.mday)<7)
						{
							//add by rfwu, remove  overdue EPG event		
							if(peitinfo->StartTime.mday == Curtime.mday)
							{
								if((peitinfo->EndTime.hour > Curtime.hour) || (peitinfo->EndTime.hour == Curtime.hour &&
									peitinfo->EndTime.minute > Curtime.minute))
								{
									if(evtCount == index)
									{
										mwOsMutexUnlock(Mutex_DvbEpg);
										return 0;
									}
									evtCount++;
								}
							}
							else
							{
								if(evtCount == index)
								{
									mwOsMutexUnlock(Mutex_DvbEpg);
									return 0;
								}
								evtCount++;
							}
						}
					}
				}
				sd=sd->next;
			}
		}
		mwOsMutexUnlock(Mutex_DvbEpg);
	}
	else
	{
		mwError("DVBEPGGetWeekdayScheInfo() - error weekday\r\n");
	}
	return -1;
}

int DVBEPGGetScheInfoByTime(dvb_service_t* SerHandle,dvb_time_t *pPlayTime, dvb_event_t* peitinfo)
{
	SECTIONDB *db;
	SECTIONDATA *sd;
	sipsi_dvbevent_t evt;
	dvb_time_t  StartTime;
	int i,ec,count=0,ptr=0;
	int s32CurTimezone = 8;

	if (SerHandle==NULL) 	return -1;

	mwOsMutexLock(Mutex_DvbEpg);
	db = DVBEPGGetScheduleDB(SerHandle);
	if(db!=NULL)
	{
		sd=db->sections;
		while(sd)
		{
			ec=SiPsiEITGetEventCount(sd->Data);			
			for(i=0; i<ec; i++)
			{
				SiPsiEITGetEvent(sd->Data, &evt, i);
				SiPsiConvertToSysTime((sipsi_systime_t*)&StartTime, evt.m_u16MjdDate, evt.m_u32UtcTime);
				DVBSysDBGetTimezone(&s32CurTimezone);
				StartTime=GetEndTime(StartTime,60*30*s32CurTimezone);
				if ( (StartTime.month==pPlayTime->month) && (StartTime.mday==pPlayTime->mday) &&
				(StartTime.hour==pPlayTime->hour) && (StartTime.second==pPlayTime->second)
				)
				{
					DVBEPGEitChg(&evt,peitinfo);
					mwOsMutexUnlock(Mutex_DvbEpg);
					return 0;
				}
			}
			sd=sd->next;
		}
	}
	mwOsMutexUnlock(Mutex_DvbEpg);
	return -1;
}


int DVBRegisterEitNotify(pEitCallback cb)
{
	EitChgCallback = cb;
	return 0;
}

int DVBEPGInit()
{
	int ret;
	ret=mwOsCreateTask("EPGTASK", 1, 0x8000, &epgThread, TRUE, (task_entry_t)DVBRecvEitTask, NULL);
	if(epgThread == (dvb_handle_t)NULL)		
	{
		mwError("DVBEPGInit() - create task faild\r\n");	
		ret = -1;
	}
	else
	{
		Mutex_DvbEpg=mwOsMutexCreate("Mutex_DvbEpg");
		DVBEPGDBCreate();
		u8EPGReceiving = 1;
	}
	return ret;
}

int DVBEPGDeinit()
{
	int ret;
	
	ret = DVBEPGStop();

	return ret;
}

